/**
 *    @file       logwrite.cpp
 *
 *    @brief      
 *    @details
 *
 *    @version    1.0
 *    @date       12/13/2012 03:44:20 PM
 *
 *    @author     Theophilus, wangtf418@gmail.com
 */
#include <stdarg.h>
#include "logwrite.h"
#include "toolkit.h"

//class logmodule================================================
logmodule::logmodule()
	: m_logtype(-1), m_filenum(DEF_LOG_FILE_NUM), m_fileindex(0),
   	m_openflag(false), m_filesize(0)
{

}

logmodule::~logmodule()
{

}

bf_int_t logmodule::init(bf_int_t logtype, const std::string &filename, bf_uint_t filenum, bf_bool_t openflag)
{
	if (logtype < 0 || filename.length() == 0 || filenum == 0)
	{
		return BF_ERROR;
	}

	if (m_logtype >= 0)
	{
		return BF_ERROR;
	}

	m_logtype = logtype;
	m_filename = filename;
	m_filenum = filenum;
	m_fileindex = 0;
	m_openflag = openflag;
	m_logfile.set_filename(filename);

	if (!m_openflag)
	{
		return BF_OK;
	}

	struct stat* filestat = m_logfile.get_filestat();
	if (filestat)
	{
		m_filesize = filestat->st_size;
	}
	else
	{
		m_filesize = 0;
	}

	bf_int_t ret = m_logfile.open("a+");
	if (ret != 0)
	{
		m_logtype = -1;
		m_filename = "";
		m_filenum = DEF_LOG_FILE_NUM;
		m_fileindex = 0;
		m_openflag = false;
		m_logfile.set_filename("");
		return BF_ERROR;
	}
	return BF_OK;
}

void logmodule::set_openflag(bf_bool_t openflag)
{
	if (m_openflag == openflag) return;
	if (m_openflag)
	{
		m_logfile.close();
		m_openflag = openflag;
	}

	struct stat* filestat = m_logfile.get_filestat();
	if (filestat)
	{
		m_filesize = filestat->st_size;
	}
	else
	{
		m_filesize = 0;
	}
	m_logfile.open("a+");
	m_openflag = openflag;
}

void logmodule::writelog(const bf_char_t *format, ...)
{
	if (!m_openflag || m_logtype < 0)
	{
		return;
	}
	m_lock.lock();
	if (m_filesize >= MAX_LOG_FILE_SIZE)
	{
		bf_char_t buf[12];
		snprintf(buf, sizeof(buf), "%02d", m_fileindex ++ % m_filenum);
		std::string dst_filename = m_logfile.get_filename() + "_" + buf;
		m_logfile.close();
		rename(m_filename.c_str(), dst_filename.c_str());
		m_filesize = 0;
	}

	if (m_logfile.get_file() == NULL && m_logfile.open("a+") != BF_OK)
	{
		m_lock.unlock();
		return;
	}
	
	bf_int_t ret = 0;
	std::string datetime = toolkit::sec2time(time(NULL));
	ret += m_logfile.print("%s: ", datetime.c_str());
	bf_valist_t ap;
	va_start(ap, format);
	ret += m_logfile.vprint(format, ap);
	va_end(ap);
	ret += m_logfile.print("\n");
	m_filesize = (ret > 0)? (m_filesize + ret):m_filesize;
	m_logfile.flush();
	m_lock.unlock();
}

//class logwrite===========================================
logmodule* logwrite::m_logmodule = NULL;
bf_int_t logwrite::m_modulenum = 0;
std::string logwrite::m_logfiledir = "";

bf_int_t logwrite::init(const std::string& logdir /* = "logs" */, bf_int_t modulenum /* = DEF_LOG_MODULE_NUM */)
{
	if (modulenum <= 0)
	{
		return BF_ERROR;
	}
	m_modulenum = modulenum;
	m_logmodule = new logmodule[m_modulenum];
	bf_int_t ret = 0;
	m_logfiledir = logdir;
	if (!m_logfiledir.empty() && m_logfiledir[m_logfiledir.length() - 1] != '/')
	{
		m_logfiledir += "/";
	}
	ret += add_logmodule(LOGTYPE_LOG, "log", DEF_LOG_FILE_NUM, true);
	ret += add_logmodule(LOGTYPE_RUNTIME, "run", DEF_LOG_FILE_NUM, false);
	ret += add_logmodule(LOGTYPE_TRACE, "trace", DEF_LOG_FILE_NUM, false);
	ret += add_logmodule(LOGTYPE_DEBUG, "debug", DEF_LOG_FILE_NUM, false);
	ret += add_logmodule(LOGTYPE_ERROR, "error", DEF_LOG_FILE_NUM, true);
	ret += add_logmodule(LOGTYPE_FILE, "file", DEF_LOG_FILE_NUM, false);
	ret += add_logmodule(LOGTYPE_SOCKET, "sock", DEF_LOG_FILE_NUM, false);
	ret += add_logmodule(LOGTYPE_DB, "db", DEF_LOG_FILE_NUM, false);
	ret += add_logmodule(LOGTYPE_MEM, "mem", DEF_LOG_FILE_NUM, false);
	ret += add_logmodule(LOGTYPE_SYS, "sys", DEF_LOG_FILE_NUM, false);
	return ret;
}

bf_int_t logwrite::add_logmodule(bf_int_t logtype, const std::string &filename, bf_uint_t filenum, bf_bool_t openflag)
{
	if (!m_logmodule || logtype < 0 || logtype >= m_modulenum)
	{
		return BF_ERROR;
	}

	return m_logmodule[logtype].init(logtype, m_logfiledir + filename, filenum, openflag);
}



